/**
 * @file pybind11_test.cpp
 * @author your name (lidanger@outlook.com)
 * @brief
 * @version 0.1
 * @date 2023-06-07
 *
 * @copyright Copyright (c) 2023
 *
 * pip install pybind11
 * g++ -shared -std=c++11 -fPIC pybind11_test.cpp -o pycpp.so `python3 -m pybind11 --includes` `python3-config --ldflags`
 */

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <iostream>
#include <math.h>

class Hello
{
public:
    Hello() {}

    void say(const std::string s)
    {
        std::cout << "hello " << s << std::endl;
    }

    void print(const std::vector<std::string> &items)
    {
        for (auto &item : items)
        {
            std::cout << item << std::endl;
        }
    }
};

int add(int i, int j)
{
    return i + j;
}

// 并发
const double pi = 3.1415926535897932384626433832795;

double rad(double d)
{
    return d * pi / 180.0;
}

double geo_distance(double lon1, double lat1, double lon2, double lat2, int test_cnt)
{
    pybind11::gil_scoped_release release; // 释放GIL锁

    double a, b, s;
    double distance = 0;

    for (int i = 0; i < test_cnt; i++)
    {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        a = radLat1 - radLat2;
        b = rad(lon1) - rad(lon2);
        s = pow(sin(a / 2), 2) + cos(radLat1) * cos(radLat2) * pow(sin(b / 2), 2);
        distance = 2 * asin(sqrt(s)) * 6378 * 1000;
    }

    // C++执行结束前恢复GIL锁
    pybind11::gil_scoped_acquire acquire;
    return distance;
}

PYBIND11_MODULE(pycpp, m)
{
    m.doc() = "pybind11 example";

    m.def("add", &add, "A function that adds two numbers");

    pybind11::class_<Hello>(m, "Hello")
        // 对应构造函数，如果没有声明或者参数不对，会导致调用失败
        .def(pybind11::init())
        .def("say", &Hello::say)
        .def("print", &Hello::print);

    m.def("geo_distance", &geo_distance, "地理距离计算");
}
